<?php

namespace App\Services\icbc;

class AES
{
    /**
     * This was AES-128 / CBC / PKCS5Padding
     * return base64_encode string
     * @param string $plaintext
     * @param string $key
     * @return string
     */
    public static function AesEncrypt($plaintext, $key = null)
    {
        $plaintext = trim($plaintext);
        if ($plaintext == '') return '';

        // 使用 AES-128-CBC 加密
        $method = 'AES-128-CBC'; // 加密方法
        $key = self::substr($key, 0, 16); // key必须是16字节
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method)); // 随机生成IV

        // PKCS7 Padding
        $padding = 16 - (strlen($plaintext) % 16);
        $plaintext .= str_repeat(chr($padding), $padding); // 添加Padding

        // 使用 OpenSSL 进行加密
        $encrypted = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);

        // 将 IV 也进行 base64 编码，方便解密时使用
        return base64_encode($iv . $encrypted);
    }

    /**
     * This was AES-128 / CBC / PKCS5Padding
     * @param string $encrypted base64_encode encrypted string
     * @param string $key
     * @return string
     */
    public static function AesDecrypt($encrypted, $key = null)
    {
        if ($encrypted == '') return '';

        $data = base64_decode($encrypted);
        $method = 'AES-128-CBC'; // 加密方法
        $key = self::substr($key, 0, 16); // key必须是16字节

        // 提取 IV 和密文
        $ivLength = openssl_cipher_iv_length($method);
        $iv = substr($data, 0, $ivLength); // 解密时需要的IV
        $ciphertext = substr($data, $ivLength); // 密文部分

        // 使用 OpenSSL 进行解密
        $decrypted = openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);

        // 去掉 PKCS7 Padding
        $padding = ord($decrypted[strlen($decrypted) - 1]);
        return substr($decrypted, 0, -$padding);
    }

    /**
     * Returns the portion of the string specified by the start and length parameters.
     * If available uses the multibyte string function mb_substr
     * @param string $string the input string. Must be one character or longer.
     * @param integer $start the starting position
     * @param integer $length the desired portion length
     * @return string the extracted part of string, or FALSE on failure or an empty string.
     */
    private static function substr($string, $start, $length)
    {
        return extension_loaded('mbstring') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
    }
}

// 示例：加密与解密
// echo AES::AesEncrypt("haha", "mkeymkeymkeymkey"); // 输出加密字符串
// echo AES::AesDecrypt("你的加密字符串", "mkeymkeymkeymkey"); // 输出解密后的字符串
